/*
 * This file is part of b.AMP.
 * 
 * b.AMP is free software: you can redistribute it and/or modify it under 
 * the terms of the GNU Lesser General Public License as published by the 
 * Free Software Foundation, either version 3 of the License, or (at your 
 * option) any later version.
 * 
 * b.AMP is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU lesser General Public 
 * License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with b.AMP.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <bamp/basic_message.hpp>
#include <bamp/value.hpp>

#include <map>
#include <memory>


typedef std::map<std::string, bamp::Value> ArgMap;


struct bamp::BasicMessage::Implementation
{
    ArgMap::const_iterator getArg(size_t index)
    {
        BAMP_ASSERT_THROW(index < args.size(), INDEX_OUT_OF_RANGE);
        ArgMap::const_iterator it = args.begin();
        for (size_t i = 0; i < index; ++i) ++it;
        return it;
    }

    std::string name;
    ArgMap      args;
};


bamp::BasicMessage::BasicMessage()
    : pimpl(new Implementation())
{
    // Nothing here
}

bamp::BasicMessage::BasicMessage(const std::string& name)
    : pimpl(new Implementation())
{
    pimpl->name = name;
}

bamp::BasicMessage::~BasicMessage()
{
    // Nothing here
}

bamp::BasicMessage::BasicMessage(const BasicMessage& msg)
    : pimpl(new Implementation())
{
    pimpl->name = msg.pimpl->name;
    pimpl->args = msg.pimpl->args;
}

bamp::BasicMessage& bamp::BasicMessage::operator=(const BasicMessage& msg)
{
    if (&msg != this)
    {
        pimpl->name = msg.pimpl->name;
        ArgMap::const_iterator it;
        
        for (it = msg.pimpl->args.begin(); it != msg.pimpl->args.end(); ++it)
        {
            pimpl->args.insert(std::make_pair(it->first, it->second.clone()));
        }        
    }
    return *this;
}

std::string bamp::BasicMessage::getName() const
{
    return pimpl->name;
}

void bamp::BasicMessage::setName(const std::string& name)
{
    pimpl->name = name;
}

size_t bamp::BasicMessage::getArgc() const
{
    return pimpl->args.size();
}

void bamp::BasicMessage::setArg(const std::string& name,
                                const bamp::Value& value)
{
    pimpl->args[name] = value;
}

bamp::Value bamp::BasicMessage::getArg(size_t index) const
{
    return pimpl->getArg(index)->second;
}

std::string bamp::BasicMessage::getArgName(size_t index) const
{
    return pimpl->getArg(index)->first;
}

bamp::Value bamp::BasicMessage::getArgByName(const std::string& name) const
{
    // Look for the value and return it if it was found.
    ArgMap::const_iterator it = pimpl->args.find(name);
    BAMP_ASSERT_THROW(it != pimpl->args.end(), NOT_FOUND);
    return it->second;
}
